package http

import (
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"gitee.com/captials-team/ubdframe/src/domain/configstc"
	"gitee.com/captials-team/ubdframe/src/domain/dto"
	"gitee.com/captials-team/ubdframe/src/domain/dto/paginate"
	"gitee.com/captials-team/ubdframe/src/domain/dto/reqdata"
	"gitee.com/captials-team/ubdframe/src/domain/dto/respdata"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/domain/models"
	"gitee.com/captials-team/ubdframe/src/pkg/gin_http"
	"gitee.com/captials-team/ubdframe/src/pkg/i18n"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"gitee.com/captials-team/ubdframe/src/pkg/passwd"
	"github.com/gin-gonic/gin"
	"golang.org/x/text/language"
	"net/http"
)

type UserController struct {
	l              v1log.ILog
	userDao        interfaces.ItfUser
	loginRecordDao interfaces.ItfUserLoginRecord
	verifyCodeDao  interfaces.ItfVerifyCode

	conf *configstc.UserAppConfig

	*gin_http.CaptchaController
	*gin_http.I18nController
	passwd.SaltMd5Password
}

func NewUserController(l v1log.ILog, conf *configstc.UserAppConfig, userDao interfaces.ItfUser, loginRecordDao interfaces.ItfUserLoginRecord, verifyCodeDao interfaces.ItfVerifyCode) *UserController {
	ctr := &UserController{
		l:               l,
		conf:            conf,
		SaltMd5Password: passwd.SaltMd5Password{Salt: conf.PasswordSalt},
	}
	//i18n
	{
		parser := i18n.NewParser()
		//parser.Bundle().MustParseMessageFileBytes([]byte(I18nEn), language.English.String()+".toml")
		//parser.Bundle().MustParseMessageFileBytes([]byte(I18nZh), language.Chinese.String()+".toml")
		//for name, path := range conf.I18nFiles {
		//	parser.Load(path, name+".toml")
		//	l.Info("load i18n path %s: %s, %s", name, path, parser.Lang(name).ParseMsg("Hello"))
		//}
		parser.SetLanguage(language.Chinese)
		parser.CacheLanguages()
		ctr.I18nController = &gin_http.I18nController{
			Parser: i18n.NewParser(),
		}
	}
	ctr.userDao = userDao
	ctr.loginRecordDao = loginRecordDao
	ctr.verifyCodeDao = verifyCodeDao

	return ctr
}

// UserInfo godoc
// @Summary      用户信息
// @Description  用户信息，比AuthInfo提供信息更详细
// @Tags         user
// @Produce      json
// @Security     ApiKeyAuth
// @success 0  {object} respdata.ResponseData{data=respdata.QueryUserResp} "获取成功"
// @success 0  {object} respdata.ResponseData{} "重置成功"
// @fail 1 {object} respdata.ResponseData{} "重置失败"
// @Router       /u_center/info [post]
func (ctr *UserController) UserInfo(ctx *gin.Context) {
	auth := gin_http.GetAuth(ctx)
	user, err := ctr.userDao.Query(auth.Id)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("query err"))
		return
	}
	if user == nil {
		ctx.JSON(http.StatusOK, respdata.CNotFound)
		return
	}

	resp := utils.CopyTo(user, new(respdata.QueryUserResp))
	ctr.Response(ctx, respdata.CSuccess.MData(resp))
}

// ResetPassword godoc
// @Summary      忘记密码
// @Description  忘记密码场景下重置密码
// @Tags         user
// @Produce      json
// @Param        param    body     reqdata.ResetPasswordReq  true  "重置密码"
// @success 0  {object} respdata.ResponseData{} "重置成功"
// @fail 1 {object} respdata.ResponseData{} "重置失败"
// @Router       /u_center/reset_pwd [post]
func (ctr *UserController) ResetPassword(ctx *gin.Context) {
	var req reqdata.ResetPasswordReq
	ctx.ShouldBind(&req)

	if req.Target() == "" {
		ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
		return
	}

	//校验验证码
	ok, err := ctr.verifyCodeDao.Verify(req.Target(), req.Code)
	if err != nil || !ok {
		ctr.l.Ctl(err != nil).Error("verify err %s", err)
		ctx.JSON(http.StatusOK, respdata.CVtCodeInvalid)
		return
	}

	//通过后进行重置
	var user *models.User
	if req.Phone != "" {
		user, err = ctr.userDao.QueryByPhone(req.Phone)
	} else if req.Email != "" {
		user, err = ctr.userDao.QueryByEmail(req.Email)
	}
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("user not exist"))
		return
	}

	if user == nil {
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("user not exist"))
		return
	}

	//重置账户密码
	if _, err := ctr.userDao.ResetPassword(user.Id, ctr.GenPassword(req.Password)); err != nil {
		ctr.l.Error("reset fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("reset fail"))
		return
	}

	ctx.JSON(http.StatusOK, respdata.CSuccess)
}

// BindEmailPhone godoc
// @Summary      用户中心-绑定邮箱/手机
// @Description  绑定邮箱/手机
// @Tags         user
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body reqdata.PhoneEmailVerifyReq  true  "验证信息"
// @success 200  {object} respdata.ResponseData{} "绑定成功"
// @success 500 {object} respdata.ResponseData{} "绑定失败"
// @Router       /u_center/bind [post]
func (ctr *UserController) BindEmailPhone(ctx *gin.Context) {
	var req reqdata.PhoneEmailVerifyReq
	ctx.ShouldBind(&req)

	if req.Email == "" || req.Phone == "" {
		ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
		return
	}

	//校验验证码
	ok, err := ctr.verifyCodeDao.Verify(req.Target(), req.Code)
	if err != nil || !ok {
		ctr.l.Ctl(err != nil).Error("verify err %s", err)
		ctx.JSON(http.StatusOK, respdata.CVtCodeInvalid)
		return
	}
	//通过后进行修改
	var user *models.User
	if req.Phone != "" {
		user, err = ctr.userDao.QueryByPhone(req.Phone)
	} else if req.Email != "" {
		user, err = ctr.userDao.QueryByEmail(req.Email)
	}
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("user not exist"))
		return
	}

	if user == nil {
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("user not exist"))
		return
	}
	if req.Phone != "" {
		user.Phone = req.Phone
	} else if req.Email != "" {
		user.Email = req.Email
	}

	//重置账户密码
	if _, err := ctr.userDao.UpdateProInfo(user.Id, &models.User{
		Email: user.Email,
		Phone: user.Phone,
	}); err != nil {
		ctr.l.Error("reset fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("reset fail"))
		return
	}

	ctx.JSON(http.StatusOK, respdata.CNotSupport)
}

// LoginRecord godoc
// @Summary      用户中心-历史登录记录
// @Description  登录历史记录
// @Tags         user
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body     reqdata.SearchLoginRecordReq  true  "搜索参数集"
// @success 200  {object} respdata.ResponseData{data=respdata.SearchListResponse{list=[]models.UserLoginRecord}} "获取成功"
// @success 500 {object} respdata.ResponseData{} "授权失败"
// @Router       /u_center/login_record [post]
func (ctr *UserController) LoginRecord(ctx *gin.Context) {
	var req reqdata.SearchLoginRecordReq
	ctx.ShouldBind(&req)

	auth := gin_http.GetAuth(ctx)
	list, pager, err := ctr.loginRecordDao.Search(&dto.SearchLoginRecordParams{
		Keywords: req.Keywords,
		Uid:      auth.Id,
	}, &paginate.Pager{
		Page: req.Page,
		Size: req.Size,
	})
	if err != nil {
		ctr.l.Error("search err %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("search fail"))
		return
	}

	ctx.JSON(http.StatusOK, respdata.CSuccess.MData(respdata.SearchListResponse{
		List:     list,
		Paginate: *pager,
	}))
}

// ModifyPassword godoc
// @Summary      用户中心-修改密码
// @Description  授权登录后修改密码
// @Tags         user
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body     reqdata.ModifyPasswordReq  true  "修改密码"
// @success 0  {object} respdata.ResponseData{} "修改成功"
// @fail 1 {object} respdata.ResponseData{} "修改失败"
// @Router       /u_center/modify_pwd [post]
func (ctr *UserController) ModifyPassword(ctx *gin.Context) {
	var req reqdata.ModifyPasswordReq
	ctx.ShouldBind(&req)

	if req.OldPassword == "" || req.Password == "" {
		ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
		return
	}

	auth := gin_http.GetAuth(ctx)
	user, err := ctr.userDao.Query(auth.Id)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError)
		return
	}

	//旧密码验证
	if user.Password != ctr.GenPassword(req.OldPassword, user.Salt) {
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("password wrong"))
		return
	}

	//重置密码
	if _, err := ctr.userDao.ResetPassword(auth.Id, ctr.GenPassword(req.Password)); err != nil {
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("password reset fail"))
		return
	}

	ctx.JSON(http.StatusOK, respdata.CSuccess)
}

// ModifyInfo godoc
// @Summary      用户中心-修改个人信息
// @Description  修改个人信息
// @Tags         user
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body     reqdata.ModifyInfoReq  true  "账户信息"
// @success 200  {object} respdata.ResponseData{} "授权成功"
// @success 500 {object} respdata.ResponseData{} "授权失败"
// @Router       /u_center/modify_info [post]
func (ctr *UserController) ModifyInfo(ctx *gin.Context) {
	var req reqdata.ModifyInfoReq
	ctx.ShouldBind(&req)

	if req.Nickname == "" || req.Avatar == "" {
		ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
		return
	}

	auth := gin_http.GetAuth(ctx)
	_, err := ctr.userDao.UpdateProInfo(auth.Id, &models.User{
		Nickname: req.Nickname,
		Sex:      req.Sex,
		Avatar:   req.Avatar,
	})
	if err != nil {
		ctr.l.Error("update fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError)
		return
	}

	ctx.JSON(http.StatusOK, respdata.CSuccess)
}
